import os
import re
import shutil
import logging
from datetime import datetime
import math

# 设置日志
logger = logging.getLogger('local_resources_utils')

class LocalResourcesUtils:
    """
    本地资源管理工具类，提供本地视频资源的管理、查询和操作功能，
    支持递归遍历子文件夹中的视频文件
    """
    
    # 默认资源目录
    DEFAULT_RESOURCE_DIR = '/app/skit'  
    
    # 仅支持的视频文件格式
    SUPPORTED_VIDEO_EXTENSIONS = [
        '.mp4', '.avi', '.mkv', '.mov', '.flv', 
        '.wmv', '.m4v', '.mpeg', '.mpg', '.webm'
    ]
    
    @classmethod
    def is_video_file(cls, filename):
        """
        判断文件是否为支持的视频文件
        
        参数:
            filename: 文件名
        
        返回:
            bool: 是视频文件返回True，否则返回False
        """
        ext = os.path.splitext(filename)[1].lower()
        return ext in cls.SUPPORTED_VIDEO_EXTENSIONS
    
    def _recursive_list_resources(self, current_dir, resource_type='all', search_query=''):
        """递归遍历目录及其子目录，收集资源信息"""
        resources = []
        
        for item in os.listdir(current_dir):
            item_path = os.path.join(current_dir, item)
            
            # 跳过隐藏文件/文件夹
            if item.startswith('.'):
                continue
            
            is_file = os.path.isfile(item_path)
            is_folder = os.path.isdir(item_path)
            
            # 过滤资源类型
            if resource_type == 'file' and not is_file:
                continue
            if resource_type == 'folder' and not is_folder:
                continue
            
            # 如果是文件，只保留视频文件
            if is_file and not self.is_video_file(item):
                continue
            
            # 搜索过滤
            if search_query and search_query.lower() not in item.lower():
                continue
            
            resource_info = {
                'name': item,
                'path': item_path,
                'is_file': is_file,
                'is_folder': is_folder,
                'last_modified': os.path.getmtime(item_path),
                'size': os.path.getsize(item_path) if is_file else None,
                'is_video': is_file and self.is_video_file(item),
                'parent_dir': current_dir
            }
            
            # 如果是视频文件，获取不带扩展名的文件名
            if is_file and self.is_video_file(item):
                resource_info['video_name'] = os.path.splitext(item)[0]
            else:
                resource_info['video_name'] = item
            
            # 如果是文件夹，递归处理子目录并统计视频数量
            if is_folder:
                # 递归获取子目录资源
                sub_resources = self._recursive_list_resources(
                    item_path, resource_type, search_query
                )
                
                # 统计子目录中的视频文件数量
                video_count = sum(1 for res in sub_resources if res['is_video'])
                
                # 检查是否有poster.jpg和nfo文件
                poster_path = None
                nfo_path = None
                has_media_file = False
                
                for f in os.listdir(item_path):
                    f_path = os.path.join(item_path, f)
                    if os.path.isfile(f_path):
                        if f.lower() == 'poster.jpg':
                            poster_path = f_path
                        elif f.lower().endswith('.nfo') and not nfo_path:
                            nfo_path = f_path
                        elif self.is_video_file(f):
                            has_media_file = True
                
                # 检查是否已刮削
                is_scraped = False
                missing_items = []
                if poster_path is not None and os.path.exists(poster_path):
                    if nfo_path is not None and os.path.exists(nfo_path):
                        if has_media_file or video_count > 0:
                            is_scraped = True
                        else:
                            missing_items.append('媒体文件')
                    else:
                        missing_items.append('NFO文件')
                else:
                    missing_items.append('封面图片')
                
                # 构建刮削状态信息
                scrape_status = {
                    'is_scraped': is_scraped,
                    'missing_items': missing_items,
                    'status_text': '已刮削' if is_scraped else '未刮削（缺少：' + ', '.join(missing_items) + '）'
                }
                
                resource_info.update({
                    'video_count': video_count,
                    'sub_resources': sub_resources,  # 子目录资源列表
                    'has_poster': poster_path is not None and os.path.exists(poster_path),
                    'has_nfo': nfo_path is not None and os.path.exists(nfo_path),
                    'has_media_file': has_media_file or video_count > 0,
                    'scrape_status': scrape_status,
                    'poster_path': poster_path,
                    'nfo_path': nfo_path
                })
            else:
                # 对于文件类型资源，判断是根目录还是文件夹内部的媒体文件
                is_scraped = False
                missing_items = []
                
                if is_file and self.is_video_file(item):
                    # 检查文件是否在根目录
                    if current_dir == self.DEFAULT_RESOURCE_DIR:
                        # 根目录的媒体文件显示为未刮削
                        missing_items.append('未组织到文件夹')
                    else:
                        # 文件夹内部的媒体文件显示为已刮削
                        is_scraped = True
                
                # 构建刮削状态信息
                scrape_status = {
                    'is_scraped': is_scraped,
                    'missing_items': missing_items,
                    'status_text': '已刮削' if is_scraped else ('未刮削（缺少：' + ', '.join(missing_items) + '）') if missing_items else '未刮削'
                }
                
                resource_info.update({
                    'video_count': 0,
                    'sub_resources': [],
                    'has_poster': False,
                    'has_nfo': False,
                    'has_media_file': is_file and self.is_video_file(item),
                    'scrape_status': scrape_status,
                    'poster_path': None,
                    'nfo_path': None
                })
            
            resources.append(resource_info)
        
        return resources
    
    def list_resources(self, resource_type='all', search_query='', sort_option='name-asc', recursive=True):
        """
        列出本地资源目录中的所有资源，支持递归遍历子文件夹
        
        参数:
            resource_type: 资源类型 ('all', 'file', 'folder')
            search_query: 搜索关键词
            sort_option: 排序方式 ('name-asc', 'name-desc', 'date-asc', 'date-desc')
            recursive: 是否递归遍历子文件夹
        
        返回:
            tuple: (是否成功, 资源列表或错误信息)
        """
        try:
            resource_dir = self.DEFAULT_RESOURCE_DIR
            
            # 检查目录是否存在
            if not os.path.exists(resource_dir):
                return False, f'资源目录不存在: {resource_dir}'
            
            # 读取目录内容（递归或非递归）
            if recursive:
                resources = self._recursive_list_resources(resource_dir, resource_type, search_query)
            else:
                # 非递归模式，只处理一级目录
                resources = []
                for item in os.listdir(resource_dir):
                    item_path = os.path.join(resource_dir, item)
                    
                    if item.startswith('.'):
                        continue
                    
                    is_file = os.path.isfile(item_path)
                    is_folder = os.path.isdir(item_path)
                    
                    if resource_type == 'file' and not is_file:
                        continue
                    if resource_type == 'folder' and not is_folder:
                        continue
                    
                    if is_file and not self.is_video_file(item):
                        continue
                    
                    if search_query and search_query.lower() not in item.lower():
                        continue
                    
                    # 基本资源信息（与递归模式保持一致的结构）
                    # 对于文件夹，检查是否有poster.jpg、nfo文件和媒体文件
                    poster_path = None
                    nfo_path = None
                    has_media_file = False
                    video_count = 0
                    
                    if is_folder:
                        for f in os.listdir(item_path):
                            f_path = os.path.join(item_path, f)
                            if os.path.isfile(f_path):
                                if f.lower() == 'poster.jpg':
                                    poster_path = f_path
                                elif f.lower().endswith('.nfo') and not nfo_path:
                                    nfo_path = f_path
                                elif self.is_video_file(f):
                                    has_media_file = True
                                    video_count += 1
                    else:
                        has_media_file = is_file and self.is_video_file(item)
                    
                    # 检查是否已刮削
                    is_scraped = False
                    missing_items = []
                    
                    if is_folder:
                        if poster_path is not None and os.path.exists(poster_path):
                            if nfo_path is not None and os.path.exists(nfo_path):
                                if has_media_file:
                                    is_scraped = True
                                else:
                                    missing_items.append('媒体文件')
                            else:
                                missing_items.append('NFO文件')
                        else:
                            missing_items.append('封面图片')
                    else:
                        # 根目录媒体文件直接显示未刮削
                        is_scraped = False
                        missing_items.append('未组织到文件夹')
                    
                    # 构建刮削状态信息
                    scrape_status = {
                        'is_scraped': is_scraped,
                        'missing_items': missing_items,
                        'status_text': '已刮削' if is_scraped else f'未刮削（缺少：{"、".join(missing_items)}）'
                    }
                    
                    resource_info = {
                        'name': item,
                        'path': item_path,
                        'is_file': is_file,
                        'is_folder': is_folder,
                        'last_modified': os.path.getmtime(item_path),
                        'size': os.path.getsize(item_path) if is_file else None,
                        'is_video': is_file and self.is_video_file(item),
                        'parent_dir': resource_dir,
                        'video_name': os.path.splitext(item)[0] if (is_file and self.is_video_file(item)) else item,
                        'sub_resources': [],
                        'video_count': video_count,
                        'has_poster': poster_path is not None and os.path.exists(poster_path),
                        'has_nfo': nfo_path is not None and os.path.exists(nfo_path),
                        'has_media_file': has_media_file,
                        'scrape_status': scrape_status,
                        'poster_path': poster_path,
                        'nfo_path': nfo_path
                    }
                    
                    resources.append(resource_info)
            
            # 排序
            if sort_option == 'name-asc':
                resources.sort(key=lambda x: x['name'].lower())
            elif sort_option == 'name-desc':
                resources.sort(key=lambda x: x['name'].lower(), reverse=True)
            elif sort_option == 'date-asc':
                resources.sort(key=lambda x: x['last_modified'])
            elif sort_option == 'date-desc':
                resources.sort(key=lambda x: x['last_modified'], reverse=True)
            
            return True, resources
        except Exception as e:
            logger.error(f'读取本地资源时发生错误: {str(e)}', exc_info=True)
            return False, str(e)
    
    def _recursive_count_videos(self, current_dir):
        """递归统计目录及其子目录中的视频文件数量"""
        count = 0
        
        for item in os.listdir(current_dir):
            item_path = os.path.join(current_dir, item)
            
            if item.startswith('.'):
                continue
            
            if os.path.isfile(item_path) and self.is_video_file(item):
                count += 1
            elif os.path.isdir(item_path):
                # 递归统计子目录
                count += self._recursive_count_videos(item_path)
        
        return count
    
    def get_resource_stats(self, recursive=True):
        """
        获取本地视频资源统计信息，支持递归统计子文件夹
        
        参数:
            recursive: 是否递归统计子文件夹
        
        返回:
            dict: 包含视频文件和文件夹数量的统计信息
        """
        try:
            resource_dir = self.DEFAULT_RESOURCE_DIR
            if not os.path.exists(resource_dir):
                return {'video_files': 0, 'folders': 0, 'total': 0}
            
            video_files = 0
            folders = 0
            
            # 统计顶层目录
            for item in os.listdir(resource_dir):
                item_path = os.path.join(resource_dir, item)
                
                if item.startswith('.'):
                    continue
                
                if os.path.isfile(item_path) and self.is_video_file(item):
                    video_files += 1
                elif os.path.isdir(item_path):
                    folders += 1
                    # 如果需要递归统计，添加子目录中的视频数量
                    if recursive:
                        video_files += self._recursive_count_videos(item_path)
            
            return {
                'video_files': video_files,
                'folders': folders,
                'total': video_files + folders,
                'recursive': recursive
            }
        except Exception as e:
            logger.warning(f"获取本地资源数量失败: {str(e)}")
            return {'video_files': 0, 'folders': 0, 'total': 0, 'recursive': recursive}
    
    # 以下方法保持不变，但会自动适应递归结构
    def check_mount_status(self):
        """检查本地资源挂载状态"""
        try:
            mount_path = self.DEFAULT_RESOURCE_DIR
            is_mounted = False
            
            if os.path.exists(mount_path) and os.path.isdir(mount_path):
                try:
                    os.listdir(mount_path)
                    is_mounted = True
                except Exception:
                    is_mounted = False
            
            return {
                'is_mounted': is_mounted,
                'mount_path': mount_path
            }
        except Exception as e:
            logger.error(f'检查本地资源挂载状态时发生错误: {str(e)}', exc_info=True)
            return {
                'is_mounted': False,
                'mount_path': self.DEFAULT_RESOURCE_DIR,
                'error': str(e)
            }
    
    def _generate_nfo_content_from_media_info(self, media_info):
        """从媒体信息生成NFO文件内容"""
        media_type = media_info.get('type', 'movie')
        root_tag = 'tvshow' if media_type == 'tv' else 'movie'
        title = media_info.get('title', media_info.get('name', 'Unknown'))
        original_title = media_info.get('original_title', media_info.get('original_name', title))
        overview = media_info.get('overview', '')
        tmdb_id = media_info.get('id', '')
        
        # 创建简单的XML内容
        nfo_content = f"<?xml version='1.0' encoding='UTF-8' standalone='yes'?><{root_tag}><title>{title}</title><originaltitle>{original_title}</originaltitle><overview>{overview}</overview><tmdbid>{tmdb_id}</tmdbid></{root_tag}>"
        return nfo_content
    
    def save_scraped_data(self, resource_path, movie_info, poster_path=None):
        """保存刮削数据到资源目录的统一入口，根据数据源类型调用相应的处理方法"""
        try:
            # 判断数据源类型
            if 'tmdb_id' in movie_info or 'media_info' in movie_info:
                # TMDB数据源
                return self._save_scraped_data_from_tmdb(resource_path, movie_info, poster_path)
            elif 'source' in movie_info and (movie_info['source'] == 'madouqu' or movie_info['source'] == 'javdb'):
                # 对madouqu和javdb数据源进行特殊处理，确保正确创建文件夹和移动文件
                logger.info(f'使用特殊处理逻辑保存{movie_info["source"]}数据源的刮削数据')
                return self._save_scraped_data_from_douban(resource_path, movie_info, poster_path)
            else:
                # 豆瓣或其他数据源
                return self._save_scraped_data_from_douban(resource_path, movie_info, poster_path)
        except Exception as e:
            logger.error(f'保存刮削数据时发生错误: {str(e)}', exc_info=True)
            return False, {
                'error': str(e),
                'progress': {'error': str(e)}
            }
    
    def _save_scraped_data_from_tmdb(self, resource_path, movie_info, poster_path=None):
        """专门处理TMDB数据源的刮削数据保存"""
        try:
            # 初始化进度状态
            progress = {
                'nfo_generated': False,
                'poster_saved': False,
                'folder_created': False,
                'files_organized': False,
                'error': None
            }
            
            if not resource_path or not movie_info:
                progress['error'] = '请提供资源路径和电影信息'
                return False, progress
            
            is_file = os.path.isfile(resource_path)
            is_video = is_file and self.is_video_file(resource_path)
            target_dir = ''
            original_file_path = resource_path if is_file else None
            
            # 步骤1: 确定目标目录和创建文件夹
            try:
                if is_video:
                    # 如果是视频文件，读取文件路径并创建资源详情标题的文件夹
                    base_dir = os.path.dirname(resource_path)
                    
                    # 处理TMDB数据源的标题获取
                    title_source = movie_info.get('media_info', movie_info)
                    video_title = title_source.get('title', title_source.get('name', '未知视频'))
                    
                    safe_title = re.sub(r'[\\/:*?"<>|]', '', video_title)
                    target_dir = os.path.join(base_dir, safe_title)
                    
                    # 创建文件夹，处理重名情况
                    if os.path.exists(target_dir):
                        counter = 1
                        while os.path.exists(os.path.join(base_dir, f"{safe_title}_{counter}")):
                            counter += 1
                        if os.path.isdir(target_dir):
                            # 如果已存在同名文件夹，则使用原文件夹
                            pass
                        else:
                            # 如果存在同名文件，则创建新文件夹
                            target_dir = os.path.join(base_dir, f"{safe_title}_{counter}")
                            os.makedirs(target_dir, exist_ok=True)
                    else:
                        os.makedirs(target_dir, exist_ok=True)
                else:
                    # 如果是文件夹，则不创建，直接使用当前文件夹路径
                    target_dir = resource_path if not is_file else os.path.dirname(resource_path)
                    if not os.path.exists(target_dir):
                        os.makedirs(target_dir, exist_ok=True)
                
                progress['folder_created'] = True
            except Exception as e:
                logger.error(f'创建文件夹时发生错误: {str(e)}', exc_info=True)
                progress['error'] = f'创建文件夹失败: {str(e)}'
                return False, progress
            
            # 步骤2: 生成和保存NFO文件
            try:
                # 从movie_info或media_info中获取标题
                title_source = movie_info.get('media_info', movie_info)
                video_title = title_source.get('title', title_source.get('name', '未知视频'))
                safe_title = re.sub(r'[\\/:*?"<>|]', '', video_title)
                nfo_filename = f"{safe_title}.nfo"
                nfo_path = os.path.join(target_dir, nfo_filename)
                
                # 确保目录存在
                os.makedirs(target_dir, exist_ok=True)
                
                # 检查是否有现成的NFO文件需要复制
                if 'nfo_path' in movie_info and os.path.exists(movie_info['nfo_path']):
                    # 复制已有的NFO文件到目标目录
                    shutil.copy2(movie_info['nfo_path'], nfo_path)
                else:
                    # 尝试从media_info生成NFO内容
                    nfo_content = self._generate_nfo_content_from_media_info(title_source)
                    with open(nfo_path, 'w', encoding='utf-8') as f:
                        f.write(nfo_content)
                
                progress['nfo_generated'] = True
            except Exception as e:
                logger.error(f'保存NFO文件时发生错误: {str(e)}', exc_info=True)
                progress['error'] = f'生成NFO文件失败: {str(e)}'
                return False, progress
            
            # 步骤3: 保存海报文件
            try:
                if poster_path and os.path.exists(poster_path):
                    # 确保目录存在
                    os.makedirs(target_dir, exist_ok=True)
                    
                    # 保存海报文件，处理重名情况
                    target_poster_path = os.path.join(target_dir, 'poster.jpg')
                    counter = 1
                    while os.path.exists(target_poster_path):
                        target_poster_path = os.path.join(target_dir, f'poster_{counter}.jpg')
                        counter += 1
                    
                    shutil.copy2(poster_path, target_poster_path)
                
                progress['poster_saved'] = True
            except Exception as e:
                logger.error(f'保存海报文件时发生错误: {str(e)}', exc_info=True)
                progress['error'] = f'保存海报文件失败: {str(e)}'
                return False, progress
            
            # 步骤4: 整理资源文件
            try:
                if is_video and original_file_path and os.path.exists(original_file_path):
                    # 如果是文件，将媒体文件移动到创建的标题文件夹中
                    original_file_name = os.path.basename(original_file_path)
                    new_file_path = os.path.join(target_dir, original_file_name)
                    
                    # 处理文件重名情况
                    counter = 1
                    while os.path.exists(new_file_path):
                        name, ext = os.path.splitext(original_file_name)
                        new_file_path = os.path.join(target_dir, f"{name}_{counter}{ext}")
                        counter += 1
                    
                    # 使用shutil.move以支持跨设备移动
                    shutil.move(original_file_path, new_file_path)
                
                progress['files_organized'] = True
            except Exception as e:
                logger.error(f'整理资源文件时发生错误: {str(e)}', exc_info=True)
                progress['error'] = f'整理资源文件失败: {str(e)}'
                return False, progress
            
            # 所有步骤完成
            return True, {
                'success': True,
                'message': '刮削数据已保存成功',
                'data': {
                    'target_dir': target_dir,
                    'is_file_processed': is_video,
                    'progress': progress
                }
            }
        except Exception as e:
            logger.error(f'保存TMDB刮削数据时发生错误: {str(e)}', exc_info=True)
            return False, {
                'error': str(e),
                'progress': progress
            }
    
    def _save_scraped_data_from_douban(self, resource_path, movie_info, poster_path=None):
        """专门处理豆瓣数据源的刮削数据保存"""
        try:
            # 初始化进度状态
            progress = {
                'nfo_generated': False,
                'poster_saved': False,
                'folder_created': False,
                'files_organized': False,
                'error': None
            }
            
            if not resource_path or not movie_info:
                progress['error'] = '请提供资源路径和电影信息'
                return False, progress
            
            is_file = os.path.isfile(resource_path)
            is_video = is_file and self.is_video_file(resource_path)
            target_dir = ''
            original_file_path = resource_path if is_file else None
            
            # 步骤1: 确定目标目录和创建文件夹
            try:
                import time
                if is_video:
                    # 如果是视频文件，读取文件路径并创建资源详情标题的文件夹
                    base_dir = os.path.dirname(resource_path)
                    
                    # 增强的标题获取逻辑，与app.py保持一致
                    logger.info(f"传入的movie_info中的标题: {movie_info.get('title')}")
                    
                    # 1. 首先尝试从movie_info中获取标题
                    video_title = movie_info.get('title', '未知视频')
                    
                    # 2. 记录初始标题信息用于调试
                    logger.info(f"获取到的初始标题: {video_title}")
                    
                    # 3. 确保标题有效，不是默认值
                    if not video_title or video_title in ['未知视频', '未知', '', '电影详情', '未知电影']:
                        logger.warning(f"发现无效标题: '{video_title}'，尝试从其他来源获取")
                        
                        # 尝试从detail_info中获取标题（如果存在）
                        if movie_info.get('detail_info') and movie_info['detail_info'].get('title'):
                            video_title = movie_info['detail_info']['title']
                            logger.info(f"从detail_info获取标题: {video_title}")
                        
                        # 尝试从original_title字段获取
                        elif movie_info.get('original_title') and movie_info['original_title'] not in ['未知视频', '未知', '', '电影详情', '未知电影']:
                            video_title = movie_info['original_title']
                            logger.info(f"从original_title获取标题: {video_title}")
                        
                        # 尝试从originaltitle字段获取
                        elif movie_info.get('originaltitle') and movie_info['originaltitle'] not in ['未知视频', '未知', '', '电影详情', '未知电影']:
                            video_title = movie_info['originaltitle']
                            logger.info(f"从originaltitle获取标题: {video_title}")
                        
                        # 尝试从nfo_content中提取
                        elif movie_info.get('nfo_content'):
                            title_match = re.search(r'<title>(.*?)</title>', movie_info['nfo_content'])
                            if title_match:
                                extracted_title = title_match.group(1).strip()
                                if extracted_title and extracted_title not in ['未知视频', '未知', '', '电影详情', '未知电影']:
                                    video_title = extracted_title
                                    logger.info(f"从NFO内容中提取标题: {video_title}")
                    
                    # 确保标题仍然有效
                    if not video_title or video_title in ['未知视频', '未知', '', '电影详情', '未知电影']:
                        # 使用一个基于时间戳的默认标题作为最后的备选
                        timestamp = int(time.time())
                        video_title = f"未知电影_{timestamp}"
                        logger.warning(f"无法获取有效标题，使用默认标题: {video_title}")
                    
                    # 记录最终用于创建文件夹的标题
                    logger.info(f"最终用于创建文件夹的标题: {video_title}")
                    
                    # 生成安全的标题，移除不合法的文件名字符
                    safe_title = re.sub(r'[\\/:*?"<>|]', '', video_title)
                    logger.info(f"生成的安全标题: {safe_title}")
                    
                    # 创建目标目录路径
                    target_dir = os.path.join(base_dir, safe_title)
                    logger.info(f"计划创建的目标目录: {target_dir}")
                    
                    # 创建文件夹，处理重名情况
                    if os.path.exists(target_dir):
                        logger.info(f"目录已存在: {target_dir}")
                        counter = 1
                        while os.path.exists(os.path.join(base_dir, f"{safe_title}_{counter}")):
                            counter += 1
                        if os.path.isdir(target_dir):
                            # 如果已存在同名文件夹，则使用原文件夹
                            logger.info(f"使用已存在的同名文件夹: {target_dir}")
                        else:
                            # 如果存在同名文件，则创建新文件夹
                            target_dir = os.path.join(base_dir, f"{safe_title}_{counter}")
                            logger.info(f"存在同名文件，创建新文件夹: {target_dir}")
                            os.makedirs(target_dir, exist_ok=True)
                    else:
                        logger.info(f"创建新文件夹: {target_dir}")
                        os.makedirs(target_dir, exist_ok=True)
                else:
                    # 如果是文件夹，则不创建，直接使用当前文件夹路径
                    target_dir = resource_path if not is_file else os.path.dirname(resource_path)
                    if not os.path.exists(target_dir):
                        os.makedirs(target_dir, exist_ok=True)
                
                progress['folder_created'] = True
            except Exception as e:
                logger.error(f'创建文件夹时发生错误: {str(e)}', exc_info=True)
                progress['error'] = f'创建文件夹失败: {str(e)}'
                return False, progress
            
            # 步骤2: 生成和保存NFO文件
            try:
                # 专门针对豆瓣数据源的NFO文件处理逻辑
                nfo_content = movie_info.get('nfo_content', '')
                if nfo_content:
                    # 使用与文件夹创建相同的增强标题逻辑
                    logger.info(f"准备保存NFO文件，当前movie_info中的标题: {movie_info.get('title')}")
                    
                    # 获取用于NFO文件命名的标题
                    video_title = movie_info.get('title', '未知视频')
                    
                    # 记录初始标题信息
                    logger.info(f"NFO文件命名初始标题: {video_title}")
                    
                    # 确保标题有效，不是默认值
                    if not video_title or video_title in ['未知视频', '未知', '', '电影详情', '未知电影']:
                        logger.warning(f"发现无效标题: '{video_title}'，尝试从其他来源获取")
                        
                        # 尝试从detail_info中获取标题（如果存在）
                        if movie_info.get('detail_info') and movie_info['detail_info'].get('title'):
                            video_title = movie_info['detail_info']['title']
                            logger.info(f"从detail_info获取NFO文件标题: {video_title}")
                        
                        # 尝试从original_title字段获取
                        elif movie_info.get('original_title') and movie_info['original_title'] not in ['未知视频', '未知', '', '电影详情', '未知电影']:
                            video_title = movie_info['original_title']
                            logger.info(f"从original_title获取NFO文件标题: {video_title}")
                        
                        # 尝试从originaltitle字段获取
                        elif movie_info.get('originaltitle') and movie_info['originaltitle'] not in ['未知视频', '未知', '', '电影详情', '未知电影']:
                            video_title = movie_info['originaltitle']
                            logger.info(f"从originaltitle获取NFO文件标题: {video_title}")
                        
                        # 尝试从nfo_content中提取
                        else:
                            title_match = re.search(r'<title>(.*?)</title>', nfo_content)
                            if title_match:
                                extracted_title = title_match.group(1).strip()
                                if extracted_title and extracted_title not in ['未知视频', '未知', '', '电影详情', '未知电影']:
                                    video_title = extracted_title
                                    logger.info(f"从NFO内容中提取标题: {video_title}")
                    
                    # 确保标题仍然有效
                    if not video_title or video_title in ['未知视频', '未知', '', '电影详情', '未知电影']:
                        # 使用一个基于时间戳的默认标题作为最后的备选
                        timestamp = int(time.time())
                        video_title = f"未知电影_{timestamp}"
                        logger.warning(f"无法获取有效标题，使用默认标题: {video_title}")
                    
                    # 记录最终用于NFO文件命名的标题
                    logger.info(f"最终用于NFO文件命名的标题: {video_title}")
                    
                    # 生成安全的标题，移除不合法的文件名字符
                    safe_title = re.sub(r'[\\/:*?"<>|]', '', video_title)
                    logger.info(f"生成的NFO文件安全标题: {safe_title}")
                    
                    # 创建NFO文件路径
                    nfo_filename = f"{safe_title}.nfo"
                    nfo_path = os.path.join(target_dir, nfo_filename)
                    logger.info(f"计划保存NFO文件的路径: {nfo_path}")
                    
                    # 确保目录存在
                    os.makedirs(target_dir, exist_ok=True)
                    
                    # 写入NFO内容
                    logger.info(f"正在写入NFO文件内容到: {nfo_path}")
                    with open(nfo_path, 'w', encoding='utf-8') as f:
                        f.write(nfo_content)
                    logger.info(f"NFO文件保存成功: {nfo_path}")
                
                progress['nfo_generated'] = True
            except Exception as e:
                logger.error(f'保存NFO文件时发生错误: {str(e)}', exc_info=True)
                progress['error'] = f'生成NFO文件失败: {str(e)}'
                return False, progress
            
            # 步骤3: 保存海报文件
            try:
                if poster_path and os.path.exists(poster_path):
                    # 确保目录存在
                    os.makedirs(target_dir, exist_ok=True)
                    
                    # 保存海报文件，处理重名情况
                    target_poster_path = os.path.join(target_dir, 'poster.jpg')
                    counter = 1
                    while os.path.exists(target_poster_path):
                        target_poster_path = os.path.join(target_dir, f'poster_{counter}.jpg')
                        counter += 1
                    
                    shutil.copy2(poster_path, target_poster_path)
                
                progress['poster_saved'] = True
            except Exception as e:
                logger.error(f'保存海报文件时发生错误: {str(e)}', exc_info=True)
                progress['error'] = f'保存海报文件失败: {str(e)}'
                return False, progress
            
            # 步骤4: 整理资源文件
            try:
                if is_video and original_file_path and os.path.exists(original_file_path):
                    # 如果是文件，将媒体文件移动到创建的标题文件夹中
                    original_file_name = os.path.basename(original_file_path)
                    new_file_path = os.path.join(target_dir, original_file_name)
                    
                    # 处理文件重名情况
                    counter = 1
                    while os.path.exists(new_file_path):
                        name, ext = os.path.splitext(original_file_name)
                        new_file_path = os.path.join(target_dir, f"{name}_{counter}{ext}")
                        counter += 1
                    
                    # 使用shutil.move以支持跨设备移动
                    shutil.move(original_file_path, new_file_path)
                
                progress['files_organized'] = True
            except Exception as e:
                logger.error(f'整理资源文件时发生错误: {str(e)}', exc_info=True)
                progress['error'] = f'整理资源文件失败: {str(e)}'
                return False, progress
            
            # 所有步骤完成
            return True, {
                'success': True,
                'message': '刮削数据已保存成功',
                'data': {
                    'target_dir': target_dir,
                    'is_file_processed': is_video,
                    'progress': progress
                }
            }
        except Exception as e:
            logger.error(f'保存豆瓣刮削数据时发生错误: {str(e)}', exc_info=True)
            return False, {
                'error': str(e),
                'progress': progress
            }
    
    @staticmethod
    def format_file_size(bytes_size):
        """格式化文件大小显示"""
        if bytes_size == 0:
            return '0 Bytes'
        
        k = 1024
        sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']
        i = int(math.floor(math.log(bytes_size) / math.log(k)))
        
        return f"{round(bytes_size / math.pow(k, i), 2)} {sizes[i]}"
